package games.catchTheCreature;

import java.util.ArrayList;
import java.util.Random;

import commonDataStructures.GridList;

import games.catchTheCreature.Point;

public class CTCBoard {

	private static final int PRESENTAGE_OF_FREE_WORLD =50;
	private GridList<CTCSquare> _board;

	private Point _pP,_cP;

	public Point getPlayerPoint(){
		return _pP;
	}
	
	public Point getCreaturePoint(){
		return _cP;
	}
	
	public void setPlayerPoint(Point p){
		_pP = p;
	}
	
	public void setCreaturePoint(Point p){
		_cP = p;
	}
	
	public CTCBoard(CTCBoard other){
		_board = new GridList<CTCSquare>(other._board);
		_pP = new Point(other._pP);
		_cP = new Point(other._cP);
	}
	
	public CTCBoard(int width,int height){
		_board = new GridList<CTCSquare>(height,width); 
		for(int i=0;i<height;i++){
			for(int j=0;j<width;j++){
				_board.set(i, j,CTCSquare.EMPTY);
			}
		}
	}

	private void initWorld(int width,int height){

		for(int i=0;i<height;i++){
			for (int j=0;j<width;j++){
				set(i, j, CTCSquare.EMPTY);
			}
		}
	}

	private void fillWorldsWithBlocks(){
		Random generator = new Random();
		for(int x=0;x<getWidth();x++){
			for(int y=0;y<getHeight();y++){
				if (get(x, y) == CTCSquare.EMPTY){
					if (generator.nextInt(100) >= PRESENTAGE_OF_FREE_WORLD){
						set(x,y,CTCSquare.BLOCK);
					}
				}
			}
		}
	}

	private boolean checkCoordinate(int x,int y,ArrayList<Point> res){
		if (!isLegalCoordinate(x, y)){
			return false;
		}
		if (get(x, y)==CTCSquare.CREATURE) return true;
		if  (get(x, y)==CTCSquare.EMPTY){
			res.add(new Point(x,y));
			set(x, y, CTCSquare.CHECKED);
		}
		return false;
	}
	private ArrayList<Point> getNextSquares(int x,int y){

		ArrayList<Point> nextSquares = new ArrayList<Point>();
		if (checkCoordinate(x-1, y, nextSquares)) return null;
		if (checkCoordinate(x, y-1, nextSquares)) return null;
		if (checkCoordinate(x+1, y, nextSquares)) return null;
		if (checkCoordinate(x, y+1, nextSquares)) return null;
		return nextSquares;
	}

	private boolean isValidWorld(){
		ArrayList<Point> bank = new ArrayList<Point>();
		ArrayList<Point> tmp = new ArrayList<Point>();
		tmp = getNextSquares(_pP.getX(), _pP.getY());
		if (tmp!=null){
			bank.addAll(tmp);
		}
		while (!bank.isEmpty() && tmp!=null){
			Point tmpPoint = bank.remove(0);
			tmp = getNextSquares(tmpPoint.getX(), tmpPoint.getY());
			if (tmp!=null ){
				bank.addAll(tmp);
			}

		}
		restoreBoard();
		return tmp==null;
	}

	private void createWorld(int width,int height){
		Random generator = new Random();
		do{
			initWorld(width,height);
			set(_pP,CTCSquare.PLAYER);
			_cP = new Point(generator.nextInt(width-1)+1,generator.nextInt(height-1)+1);
			set(_cP,CTCSquare.CREATURE);
			fillWorldsWithBlocks();
		}while (!isValidWorld());
	}
	public void generateBoard(int pX,int pY){
		_pP = new Point(pX,pY);
		createWorld(getWidth(), getHeight());
	}

	public int getWidth(){
		return _board.size(0);
	}

	public int getHeight(){
		return _board.size();
	}
	public void set(Point p,CTCSquare type){
		set(p.getX(),p.getY(),type);
	}
	public void set(int x,int y, CTCSquare type){
		_board.set(y, x, type);
	}

	public CTCSquare get(int x,int y){
		return _board.get(y, x);
	}

	public void restoreBoard(){
		for(int i=0;i<_board.size();i++){
			for(int j=0;j<_board.size(0);j++){
				if (_board.get(i, j)==CTCSquare.CHECKED){
					_board.set(i, j, CTCSquare.EMPTY);
				}
			}
		}
	}

	public void printWorld(){
		for(int i=_board.size()-1;i>=0;i--){
			for(int j=0;j<_board.size(0);j++){
				switch (_board.get(i, j)){
				case BLOCK: System.out.print("#");break;
				case PLAYER: System.out.print("P");break;
				case CREATURE: System.out.print("C");break;
				case EMPTY: System.out.print(" ");break;
				case CHECKED: System.out.print("@");break;
				}
			}
			System.out.println("|");
		}
		for(int j=0;j<_board.size(0);j++){
			System.out.print("-");
		}
		System.out.println();
	
	}

	public boolean isLegalCoordinate(int x,int y){
		return !(x<0 || y<0 || x>=getWidth() || y>=getHeight());
	}

	public boolean canStepOn(Point p){
		return canStepOn(p.getX(),p.getY());
	}
	
	public boolean canPlayerStepOn(int x,int y){
		return (isLegalCoordinate(x, y) && (get(x,y)!=CTCSquare.BLOCK));
	}
	
	public boolean canCreatureStepOn(int x,int y){
		return (isLegalCoordinate(x, y) && (get(x,y)==CTCSquare.EMPTY));
	}

	public boolean canStepOn(int x,int y){
		return (isLegalCoordinate(x, y) && (get(x,y)==CTCSquare.EMPTY||get(x,y)==CTCSquare.CREATURE));
	}

	public GridList<Integer> getArrMap(){
		
		GridList<Integer> res = new GridList<Integer>(getWidth(),getHeight());
		for(int x=0;x<getWidth();x++){
			for(int y=0;y<getHeight();y++){
				res.set(y, x, get(x, y)==CTCSquare.BLOCK?-1:-2);
			}
		}
		return res;
	}

}